package main

import (
	"fmt"
	"gostu/tcp_server/frame"
	"gostu/tcp_server/packet"
	"net"
	"sync"
	"time"

	"github.com/lucasepe/codename"
)

func main() {
	var wg sync.WaitGroup
	var num int = 5

	wg.Add(num)

	for i := 0; i < num; i++ {
		go func(i int) {
			defer wg.Done()
			startClient(i)
		}(i + 1)
	}
	wg.Wait()
}

func startClient(i int) {
	quit := make(chan struct{})
	done := make(chan struct{})

	Conn, err := net.Dial("tcp", ":8888")
	if nil != err {
		fmt.Println("get the Dial error:", err)
		return
	}
	defer Conn.Close()

	// 获取到连接，开始数据传输

	// 数据制造
	rng, err := codename.DefaultRNG() // 先随机点东西出来
	if nil != err {
		panic(err)
	}

	// 封帧
	myFrame := frame.NewMyFrame()
	var count int

	// 接收
	go func() {
		for {
			select {
			case <-quit:
				done <- struct{}{}
				return
			default:
			}
			// 设置读超时
			Conn.SetReadDeadline(time.Now().Add(time.Second * 5)) // 这里调用的就是自己的方法
			ackFramePayload, err := myFrame.Decode(Conn)
			if nil != err {
				// 需要判断是否为超时——服务端会做好超时重传机制
				if e, ok := err.(net.Error); ok {
					if e.Timeout() {
						continue
					}
				}
				panic(err)
			}

			// 得到frame帧，获得数据包packet
			pkt, err := packet.Decode(ackFramePayload)
			if nil != err {
				fmt.Printf("client[%d] the packet decode error", i)
				return
			}

			submitAck, ok := pkt.(*packet.SubmitAck)
			if !ok {
				panic("not submitAck")
			}
			fmt.Printf("client[%d] get the ack, commandID = %v and res is %d\n", i, submitAck.ID, submitAck.Result)
		}
	}()

	// 发送
	for {
		count++
		id := fmt.Sprintf("%08d", count) // 8 byte string
		payload := codename.Generate(rng, 4)

		// 创建packet
		s := &packet.Submit{
			ID:      id,
			Payload: []byte(payload),
		}

		// 封帧
		myFramePayload, err := packet.Encode(s)
		if nil != err {
			fmt.Println("Encode the Frame error")
			return
		}

		fmt.Printf("[client %d]: send submit id = %s , payload=%s , frame length = %d\n",
			i, s.ID, s.Payload, len(myFramePayload)+4)

		// 发送（写入IO接口）
		err = myFrame.Encode(Conn, myFramePayload)
		if nil != err {
			fmt.Println("frame encode error, client: ", i)
			return
		}

		time.Sleep(1 * time.Second)

		if count >= 10 {
			quit <- struct{}{} // 表示关闭系统，各个协程收到退出通知
			<-done             // 等待各方退出完毕
			fmt.Printf("[client:%d]:exit ok!\n", i)
			return
		}

	}

}
